#define debug 1  //端口回显开关 1位开启 0 关闭
#define intervaltime 10 // 防抖动时间差，单位毫秒。
#define rows 4 // 按鍵模組的列數
#define cols 4 // 按鍵模組的行數
/* key value */
#define KEY_LEFT_CTRL   0x80
#define KEY_LEFT_SHIFT    0x81
#define KEY_LEFT_ALT    0x82
#define KEY_LEFT_GUI    0x83
#define KEY_RIGHT_CTRL    0x84
#define KEY_RIGHT_SHIFT   0x85
#define KEY_RIGHT_ALT   0x86
#define KEY_RIGHT_GUI   0x87

#define KEY_A       4
#define KEY_B       5
#define KEY_C       6
#define KEY_D       7
#define KEY_E       8
#define KEY_F       9
#define KEY_G       10
#define KEY_H       11
#define KEY_I       12
#define KEY_J       13
#define KEY_K       14
#define KEY_L       15
#define KEY_M       16
#define KEY_N       17
#define KEY_O       18
#define KEY_P       19
#define KEY_Q       20
#define KEY_R       21
#define KEY_S       22
#define KEY_T       23
#define KEY_U       24
#define KEY_V       25
#define KEY_W       26
#define KEY_X       27
#define KEY_Y       28
#define KEY_Z       29
#define KEY_1       30
#define KEY_2       31
#define KEY_3       32
#define KEY_4       33
#define KEY_5       34
#define KEY_6       35
#define KEY_7       36
#define KEY_8       37
#define KEY_9       38
#define KEY_0       39

#define KEY_ENTER   40

#define KEY_SPACE   44

#define KEY_F1      58
#define KEY_F2      59
#define KEY_F3      60
#define KEY_F4      61
#define KEY_F5      62
#define KEY_F6      63
#define KEY_F7      64
#define KEY_F8      65
#define KEY_F9      66
#define KEY_F10     67
#define KEY_F11     68
#define KEY_F12     69

#define KEY_ARROW_LEFT 0x50
#define KEY_ARROW_RIGHT 0x4F
#define KEY_ARROW_UP 0x52
#define KEY_ARROW_DOWN 0x51


// 
const char key_value_list[rows][cols] = {
  {49,50,51,65},  
  {52,53,54,66},
  {55,56,57,67},
  {42,48,35,68}
};

/* 键盘结构
   为了更好的查看效果，key_value_list 中使用了asc码， 实际使用中，上面的数字应替换为实际按键码
---------
|1|2|3|A|
|4|5|6|B|
|7|8|9|C|
|*|0|#|D|
---------
*/

byte key_status_list[rows][cols];
unsigned long key_time_list[rows][cols];                                
 
int btn_pin_cols[cols] = { 9,10,11,12};
int btn_pin_rows[rows]={ 3,6,7,8};

/////////////// 这里是一些功能键，由于功能键不会多键同时按下，所以这里直接使用模拟接口判断输入的电阻阻值（或者电压）

char key_value_list_fun[]={KEY_SPACE,KEY_F1,KEY_F2,KEY_F3,KEY_F4,KEY_F5,KEY_F6,KEY_F7,KEY_F8,KEY_F9,KEY_F10,KEY_F11,KEY_F12};
int  key_param_list_fun[]={50,100,150,200,250,300,350,400,450,500,550,600,650};//对应的阻值，为了防止电阻阻值浮动，在判断时可以判断上下20欧姆的区间


void _getkeystatus();//此处开始仅仅是为了返回扫描键的按键情况的一个数组，为了简单，就直接都写在这里面了。
void delayMs(unsigned int ms);

void setup() {
  // 这里使用想改为寄存器版，刚开始看这方面，就先这样吧
  
  for (int col_i=0;col_i<cols;col_i++)
     {           
            pinMode(btn_pin_cols[col_i], OUTPUT);
            digitalWrite(btn_pin_cols[col_i], HIGH);

     }
     
   for (int row_i=0;row_i<rows;row_i++)
     {           

            pinMode(btn_pin_rows[row_i], INPUT_PULLUP);
            digitalWrite(btn_pin_rows[row_i], HIGH);
     }    
     
   if (debug==1)
    {
    Serial.begin(9600);
    Serial.println("keyboard test!");}
    
 for (int col_i=0;col_i<cols;col_i++)
     {     
       for (int row_i=0;row_i<rows;row_i++)
           {    
             key_status_list[row_i][col_i]=0;
             key_time_list[row_i][col_i]=millis();
           }
     }     
             

           
}

void loop() {


  _getkeystatus();

 delayMs(20);   
}

void _getkeystatus(){
   String keyvalue; 
  
  for (int col_i=0;col_i<cols;col_i++)
     {
       digitalWrite(btn_pin_cols[col_i],LOW);
       for (int row_i=0;row_i<rows;row_i++)
           {
             keyvalue=String(key_value_list[row_i][col_i]);
             
             byte scanVal = digitalRead(btn_pin_rows[row_i]);
              if ( (scanVal==LOW)&& (key_status_list[row_i][col_i]!=1) ){
                 if ((millis()-key_time_list[row_i][col_i])>intervaltime) 
                   {
                       key_status_list[row_i][col_i]=1;
                      key_time_list[row_i][col_i]=millis();
                      if (debug==1)
                      { Serial.println(keyvalue+" :keydown");}  
                    
                       
                   }    
                  
              }
              if  ( (scanVal==HIGH)&& (key_status_list[row_i][col_i]==1) ){
                  if ((millis()-key_time_list[row_i][col_i])>intervaltime) 
                   {
                      if (debug==1)
                       { Serial.println(keyvalue+" :keyup");}
                      key_status_list[row_i][col_i]=0; 
                      key_time_list[row_i][col_i]=millis();
                   }    
                  
              }
           }
      digitalWrite(btn_pin_cols[col_i], HIGH);
     } 
}

void delayMs(unsigned int ms) {
  for( int i=0; i<ms; i++ ) {
    delayMicroseconds(1000);
  }

//功能按键还没有写,使用A2,实际应用中可能很少会用到这么多

//遥感的方向键，使用A0,A1  

//扫描方式的键盘不适合掌机使用，掌机最好直接使用数字接口判断按键状态，但现在我用的328pu接口少了些，换一个32u4就好了。
}
